﻿using System;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using System.Xml.Serialization;
using CXMLStudioIDE.BusinessLayer;
using CXMLStudioIDE.Common;
using CXMLStudioIDE.Common.Entities;
using CXMLStudioIDE.Common.EntityProperties;

namespace CXMLStudioIDE.WinFormsUI.CXMLStudioControls
{
    public partial class CXMLTreeView : TreeView, ICloneable
    {
        #region Property declarations

        //Create a Class level variable for storing Property Collection
        private readonly PropertySetCollection PropertySetCollectionObject = new PropertySetCollection();
        private readonly BackgroundWorker m_worker;
        private ArrayList NodesArray;
        //Create Object to Business Layer
        private PropertiesBL PropBL = new PropertiesBL();
        private string _ObjectName = "";
        private string _RootNodeName = "";
        // Define an Event based on the above Delegate
        private Hashtable m_bindings;
        public event OnSelectNode SelectionChanged;

        #endregion

        #region Public Properties

        public DisplayContext DisplayContext { get; set; }

        public PropertySet SelectedPropertySet { get; set; }

        public Color BaseColor { get; set; }

        public string ObjectName
        {
            get { return _ObjectName; }
            set { _ObjectName = value; }
        }

        public string RootNodeName
        {
            get { return _RootNodeName; }
            set { _RootNodeName = value; }
        }

        /* Added Import functionality to import Entities to DB as tree is built  12/14/2009 */
        public bool ImportToDB { get; set; }

        public int TreeViewId { get; set; }

        #endregion

        //Define a delegate for other windows to handle the event.

        #region Delegates

        public delegate void OnSelectNode(object sender, PropertySet selectedPropertySet);

        public delegate void OnTreeNodeHoverEventHandler(object sender, TreeNodeMouseHoverEventArgs e);

        public delegate void OnTreeViewMouseMoveEventHandler(object sender, MouseEventArgs args);

        public delegate void OnTreeViewUpdatedEventHandler(object sender, TreeviewWorkerArgs args);

        #endregion

        #region events

        public event OnTreeViewUpdatedEventHandler OnTreeViewUpdated;
        public event OnTreeNodeHoverEventHandler OnTreeNodeHover;
        public event OnTreeViewMouseMoveEventHandler OnTreeViewMouseMove;

        #endregion

        #region Constructors

        public CXMLTreeView()
        {
            InitializeComponent();
            m_worker = new BackgroundWorker();
            m_worker.DoWork += m_worker_DoWork;
            m_worker.RunWorkerCompleted += m_worker_RunWorkerCompleted;
        }

        #endregion

        #region Background worker section

        #region Nested type: AddNodeDelegate

        private delegate void AddNodeDelegate(CXMLTreeNode node);

        #endregion

        #region Nested type: AddNodeToParentDelegate

        private delegate void AddNodeToParentDelegate(CXMLTreeNode parent, CXMLTreeNode child);

        #endregion

        #region Nested type: BindToTreeDelegate

        private delegate void BindToTreeDelegate(
            object data, Type t1, CXMLTreeNode ParentNode, BusinessEntity RootEntity);

        private delegate void GoldBindToTreeDelegate(
            object data, Type t1, ref CXMLTreeNode ParentNode, BusinessEntity RootEntity);
        #endregion

        #region Nested type: ClearNodesDelegate

        private delegate void ClearNodesDelegate();

        #endregion

        #region Nested type: ConfigureGoldTreeDelegate

        private delegate void ConfigureGoldTreeDelegate(CXMLTreeView treeview);

        #endregion

        #region BackgroundWorker Methods

        private void m_worker_DoWork(object o, DoWorkEventArgs e)
        {
            var tvwa = e.Argument as TreeviewWorkerArgs;
            if (tvwa != null)
            {
                UpdateTreeView(tvwa);
                e.Result = tvwa;
            }
        }

        private void m_worker_RunWorkerCompleted(object o, RunWorkerCompletedEventArgs e)
        {
            /** Fire the event OnTreeViewUpdated **/
            OnTreeViewUpdated(this, e.Result as TreeviewWorkerArgs);
        }

        public void UpdateTreeView(BusinessEntity be, DisplayContext context, Type EntityType, object instance)
        {
            if (m_worker != null)
            {
                var args = new TreeviewWorkerArgs(be, context, EntityType,instance);
                m_worker.RunWorkerAsync(args);
            }
        }

        private void AddNodeToParent(CXMLTreeNode parent, CXMLTreeNode child)
        {
            Invoke((MethodInvoker) delegate { parent.Nodes.Add(child); }
                );
        }

        private void AddGoldNodeToParent(CXMLTreeNode parent, CXMLTreeNode child)
        {
            Invoke((MethodInvoker) delegate
                                       {
                                           if (!child.DisplayInForm)
                                           {
                                               foreach (CXMLTreeNode n in child.Nodes)
                                               {
                                                   parent.Nodes.Add(n);
                                               }
                                           }
                                           else
                                           {
                                               parent.Nodes.Add(child);
                                           }
                                       }
                );
        }

        private void MyAddNode(CXMLTreeNode node)
        {
            Invoke((MethodInvoker) delegate { Nodes.Add(node); });
        }

        private void ClearNodes()
        {
            Invoke((MethodInvoker) delegate { Nodes.Clear(); });
        }

        private void SetRootNodeNameAndColor(string NodeName)
        {
            Invoke((MethodInvoker) delegate { RootNodeName = NodeName; });
            Invoke((MethodInvoker) delegate { BaseColor = Color.DarkGray; });
        }

        #endregion

        #region Nested type: HandlePropertiesDelegate

        private delegate void HandlePropertiesDelegate(CXMLTreeNode n, PropertiesBL propBL, DisplayContext context);

        #endregion

        #region Nested type: SetRootNodeNameAndColorDelegate

        private delegate void SetRootNodeNameAndColorDelegate(string NodeName);

        #endregion

        #endregion

        #region Methods

        private void GoldBindToTree(object data, Type t1, CXMLTreeNode ParentNode, BusinessEntity RootEntity)
        {
            var node = new CXMLTreeNode();
            var fieldNode = new CXMLTreeNode();
            var propertyNode = new CXMLTreeNode();
            //Set the business entity for this node, getting it from the RootEnity collection
            node.BusinessEntity = RootEntity.GetInnerBusinessEntityByName(t1.Name);
            //node.BindingName = t1.Name + "." + node.Name;
            //Debug.WriteLine("TYPE:" + t1.Name + " BASETYPE:" + t1.BaseType + "PARENTNODE:" + ParentNode.Name);
            //Debug.WriteLine(ParentNode.Name);

            if (t1.BaseType.FullName != "System.Object")
            {
                node.Name = t1.Name;
                node.ForeColor = BaseColor;
                switch (t1.BaseType.FullName)
                {
                    case "System.Object":
                        BaseColor = Color.Black;
                        break;
                    default:
                        BaseColor = Color.DarkGray;
                        break;
                }
                if ((node.BusinessEntity != null && !node.BusinessEntity.EntityType.IsBusinessEntity) ||
                    ParentNode.Name.Equals(t1.FullName))
                {
                    GoldBindToTree(data, t1.BaseType, node, RootEntity);
                }
            }
            node.Text = t1.Name;
            node.ForeColor = BaseColor;

            if (BaseColor == Color.DarkGray)
            {
                node.DisplayInForm = false;
            }

            int i_entityTypeVerisonID = 0;

            if (node.BusinessEntity != null)
            {
                i_entityTypeVerisonID = Convert.ToInt32(node.BusinessEntity.EntityTypeVersions.EntityTypeVersionsID);
            }

            FieldInfo[] fieldInfo = t1.GetFields();
            PropertyInfo[] propertyInfo = t1.GetProperties();
            //Handle Attributes
            foreach (FieldInfo info in fieldInfo)
            {
                Object[] attributes = info.GetCustomAttributes(typeof(XmlAttributeAttribute), false);

                if (((IList)attributes).Count > 0 && info.DeclaringType.Name == t1.Name)
                {
                    fieldNode = null;
                    fieldNode = new CXMLTreeNode(((XmlAttributeAttribute)(attributes[0])).AttributeName);
                    fieldNode.ForeColor = Color.DarkGray;
                    fieldNode.Name = info.ReflectedType.Name;
                    node.Nodes.Add(fieldNode);
                    NodesArray.Add(fieldNode);

                    fieldNode.DisplayInForm = true;
                    fieldNode.BusinessEntity = RootEntity.GetInnerBusinessEntityByName(fieldNode.Name);
                }
            }
            //Handle Child Elements

            foreach (PropertyInfo info in propertyInfo)
            {
                if (info.DeclaringType.Name == t1.Name)
                {
                    propertyNode = null;
                    propertyNode = new CXMLTreeNode(info.Name);

                    propertyNode.ForeColor = Color.Black;
                    propertyNode.Name = info.Name;

                    propertyNode.BusinessEntity = RootEntity.GetInnerBusinessEntityByName(propertyNode.Name);

                    if (info.GetCustomAttributes(typeof(XmlAttributeAttribute), false).Length > 0)
                    {
                        var IFont = new Font("Microsoft Sans Serif", (float)8.25, FontStyle.Italic);
                        propertyNode.NodeFont = IFont;
                        propertyNode.IsAttribute = true;
                    }
                    if (!info.PropertyType.UnderlyingSystemType.IsPrimitive &&
                        !(info.PropertyType.UnderlyingSystemType.Namespace == "System"))
                    {
                        Type pt = info.PropertyType.UnderlyingSystemType;
                        GoldBindToTree(data, pt, propertyNode, RootEntity);
                    }
                    /** PropertyType property stores the type of data this
                     * will help when building forms and create corresponding elements **/
                    propertyNode.PropertyType = info.PropertyType.Name;
                    //Debug.WriteLine("PropertyType:" + propertyNode.PropertyType);
                    node.Nodes.Add(propertyNode);
                    NodesArray.Add(propertyNode);
                }
            }

            fieldInfo = null;
            propertyInfo = null;
            //Debug.WriteLine("Adding node: " + node.Text + " to parent: " + ParentNode.Name);
            AddNodeToParent(ParentNode, node);
            //AddGoldNodeToParent(ParentNode, node);
        }

        private void DefaultBindToTree(object data, Type t1, CXMLTreeNode ParentNode, BusinessEntity RootEntity)
        {
            var node = new CXMLTreeNode();
            var fieldNode = new CXMLTreeNode();
            var propertyNode = new CXMLTreeNode();
            //Set the business entity for this node, getting it from the RootEnity collection
            node.BusinessEntity = RootEntity.GetInnerBusinessEntityByName(t1.Name);
            //node.BindingName = t1.Name + "." + node.Name;
            //Debug.WriteLine("TYPE:" + t1.Name + " BASETYPE:" + t1.BaseType + "PARENTNODE:" + ParentNode.Name);
            //Debug.WriteLine(ParentNode.Name);

            if (t1.BaseType.FullName != "System.Object")
            {
                node.Name = t1.Name;
                node.ForeColor = BaseColor;
                switch (t1.BaseType.FullName)
                {
                    case "System.Object":
                        BaseColor = Color.Black;
                        break;
                    default:
                        BaseColor = Color.DarkGray;
                        break;
                }
                if ((node.BusinessEntity != null && !node.BusinessEntity.EntityType.IsBusinessEntity) ||
                    ParentNode.Name.Equals(t1.FullName))
                {
                    DefaultBindToTree(data, t1.BaseType, node, RootEntity);
                }
            }

            node.Text = t1.Name;
            node.ForeColor = BaseColor;

            if (BaseColor == Color.DarkGray)
            {
                node.DisplayInForm = false;
            }

            FieldInfo[] fieldInfo = t1.GetFields();
            PropertyInfo[] propertyInfo = t1.GetProperties();
            //Handle Attributes
            foreach (FieldInfo info in fieldInfo)
            {
                Object[] attributes = info.GetCustomAttributes(typeof (XmlAttributeAttribute), false);

                if (((IList) attributes).Count > 0 && info.DeclaringType.Name == t1.Name)
                {
                    fieldNode = new CXMLTreeNode(((XmlAttributeAttribute) (attributes[0])).AttributeName);
                    fieldNode.ForeColor = Color.DarkGray;
                    fieldNode.Name = info.ReflectedType.Name;
                    node.Nodes.Add(fieldNode);
                    NodesArray.Add(fieldNode);

                    fieldNode.DisplayInForm = true;
                    fieldNode.BusinessEntity = RootEntity.GetInnerBusinessEntityByName(fieldNode.Name);
                }
            }
            //Handle Child Elements

            foreach (PropertyInfo info in propertyInfo)
            {
                if (info.DeclaringType.Name == t1.Name)
                {
                    propertyNode = new CXMLTreeNode(info.Name);

                    propertyNode.ForeColor = Color.Black;
                    propertyNode.Name = info.Name;
                    //Debug.WriteLine("PropertyName:" + propertyNode.Name);

                    propertyNode.BusinessEntity = RootEntity.GetInnerBusinessEntityByName(propertyNode.Name);

                    if (info.GetCustomAttributes(typeof (XmlAttributeAttribute), false).Length > 0)
                    {
                        var IFont = new Font("Microsoft Sans Serif", (float) 8.25, FontStyle.Italic);
                        propertyNode.NodeFont = IFont;
                        propertyNode.IsAttribute = true;
                    }
                    if (!info.PropertyType.UnderlyingSystemType.IsPrimitive &&
                        info.PropertyType.UnderlyingSystemType.Namespace != "System")
                    {
                        Type pt = info.PropertyType.UnderlyingSystemType;
                        DefaultBindToTree(data, pt, propertyNode, RootEntity);
                    }
                    /** PropertyType property stores the type of data this
                     * will help when building forms and create corresponding elements **/
                    propertyNode.PropertyType = info.PropertyType.Name;
                    //Debug.WriteLine("PropertyType:" + propertyNode.PropertyType);
                    node.Nodes.Add(propertyNode);
                    NodesArray.Add(propertyNode);
                }
            }

            fieldInfo = null;
            propertyInfo = null;
            //Debug.WriteLine("Adding node: " + node.Text + " to parent: " + ParentNode.Text);
            AddNodeToParent(ParentNode, node);
        }

        private void BindToTree(object data, Type t1, CXMLTreeNode ParentNode)
        {
            var node = new CXMLTreeNode();
            var fieldNode = new CXMLTreeNode();
            var propertyNode = new CXMLTreeNode();

            if (t1.BaseType.FullName != "System.Object")
            {
                node.Name = t1.Name;
                node.ForeColor = BaseColor;
                switch (t1.BaseType.FullName)
                {
                    case "System.Object":
                        BaseColor = Color.Black;
                        break;
                    default:
                        BaseColor = Color.DarkGray;
                        break;
                }
                if (ParentNode.Name.Equals(t1.Name))
                {
                    BindToTree(data, t1.BaseType, node);
                }
            }
            node.Text = t1.Name;
            node.ForeColor = BaseColor;

            if (BaseColor == Color.DarkGray)
            {
                node.DisplayInForm = false;
            }

            FieldInfo[] fieldInfo = t1.GetFields();
            PropertyInfo[] propertyInfo = t1.GetProperties();
            //Handle Attributes
            foreach (FieldInfo info in fieldInfo)
            {
                Object[] attributes = info.GetCustomAttributes(typeof (XmlAttributeAttribute), false);

                if (((IList) attributes).Count > 0 && info.DeclaringType.Name == t1.Name)
                {
                    fieldNode = null;
                    fieldNode = new CXMLTreeNode(((XmlAttributeAttribute) (attributes[0])).AttributeName);
                    fieldNode.ForeColor = Color.DarkGray;
                    fieldNode.Name = info.ReflectedType.Name;
                    node.Nodes.Add(fieldNode);
                    fieldNode.DisplayInForm = true;
                }
            }
            //Handle Child Elements

            foreach (PropertyInfo info in propertyInfo)
            {
                if (info.DeclaringType.Name == t1.Name)
                {
                    propertyNode = null;
                    propertyNode = new CXMLTreeNode(info.Name);
                    propertyNode.ForeColor = Color.Black;
                    propertyNode.Name = info.Name;

                    if (info.GetCustomAttributes(typeof (XmlAttributeAttribute), false).Length > 0)
                    {
                        var IFont = new Font("Microsoft Sans Serif", (float) 8.25, FontStyle.Italic);
                        propertyNode.NodeFont = IFont;
                        propertyNode.IsAttribute = true;
                    }
                    if (!info.PropertyType.UnderlyingSystemType.IsPrimitive &&
                        !(info.PropertyType.UnderlyingSystemType.Namespace == "System"))
                    {
                        Type pt = info.PropertyType.UnderlyingSystemType;
                        BindToTree(data, pt, propertyNode);
                    }
                    /** PropertyType property stores the type of data this
                     * will help when building forms and create corresponding elements **/
                    propertyNode.PropertyType = info.PropertyType.Name;
                    //Debug.WriteLine("PropertyType:" + propertyNode.PropertyType);
                    node.Nodes.Add(propertyNode);
                }
            }

            fieldInfo = null;
            propertyInfo = null;
            ParentNode.Nodes.Add(node);
        }

        public void PrepareForInstances(Type t, BusinessEntity be, CXMLTreeNode RootNode)
        {
            try
            {
                /** First build the entity type for this business entity **/
                var be_builder = new BusinessEntityBuilder();
                Type t_BusinessEntityType = null;

                t_BusinessEntityType = (t == null ? be_builder.GetBusinessEntityType(be) : t);
                SetRootNodeNameAndColor(RootNode.Name);
                BindToTree(null, t_BusinessEntityType, RootNode);
            }
            catch (Exception ex)
            {
            }
        }

        private void UpdateTreeView(TreeviewWorkerArgs args)
        {
            try
            {
                /** First build the entity type for this business entity **/
                var be_builder = new BusinessEntityBuilder();
                Type t_BusinessEntityType = null;
                BindToTreeDelegate bttd = null;
                GoldBindToTreeDelegate gbttd = null;

                t_BusinessEntityType = (args.EntityType == null
                                            ? be_builder.GetBusinessEntityType(args.BusinessEntity)
                                            : args.EntityType);
                //We don't want to append elements to tree from other projects
                //So we clear the nodes before building tree.
                //this.Nodes.Clear();
                ClearNodes();
                //this.PropertySetCollectionObject.Clear();

                string szBusinessEntityName = t_BusinessEntityType.Name;

                var RootNode = new CXMLTreeNode(szBusinessEntityName);
                RootNode.Name = t_BusinessEntityType.FullName;
                RootNode.Text = szBusinessEntityName;

                RootNode.DisplayInForm = false;
                RootNode.Tag = args.BusinessEntity.EntityTypeVersions.EntityTypeVersionsID;
                //AddNodeDelegate and = new AddNodeDelegate(MyAddNode);
                //this.Invoke(and, RootNode);
                MyAddNode(RootNode);
                //this.Invoke(UpdateTree,new object[]{RootNode.Name});
                //this.Nodes.Add(RootNode);

                SetRootNodeNameAndColor(RootNode.Name);
                //this.RootNodeName = RootNode.Name;
                //this.BaseColor = System.Drawing.Color.DarkGray;

                RootNode.BusinessEntity = args.BusinessEntity;
                RootNode.EntityType = t_BusinessEntityType;

                NodesArray = new ArrayList();
                /** The following code will create a hashtable to map
                * control unique identifiers to their corresponding databinding name **/
                m_bindings = new Hashtable();

                /** Decide which BindToTree to use depending on the DisplayContext **/
                switch (args.DisplayContext)
                {
                    case DisplayContext.Deafult:
                        bttd = new BindToTreeDelegate(DefaultBindToTree);
                        break;
                    case DisplayContext.GoldCXML:
                        bttd = new BindToTreeDelegate(GoldBindToTree);
                        break;
                    case DisplayContext.FormDesigner:
                        bttd = new BindToTreeDelegate(DefaultBindToTree);
                        break;
                }
                if (bttd != null)
                {
                    Invoke(bttd, null, t_BusinessEntityType, RootNode, args.BusinessEntity);
                }
                //if (gbttd != null)
                //{
                //    object instance = null;
                //    if(args.Instance == null)
                //    {
                //        instance = Activator.CreateInstance(t_BusinessEntityType);
                //    }else
                //    {
                //        instance = args.Instance;
                //    }
                //    Invoke(gbttd, instance, t_BusinessEntityType, RootNode, args.BusinessEntity);
                //}
                NodesArray.Add(RootNode);

                #region Create and assign ControlBindings map to root node

                var propBL = new PropertiesBL();

                /** Get Node Lineage for each element which will be used
                ** to give a unique name to controls **/
                foreach (CXMLTreeNode n in NodesArray)
                {
                    string lineage = "";
                    if (n.BusinessEntity != null)
                    {
                        lineage = n.GetNodeLineage();
                        /** Loads the bindings Hashtable that will map the binding name
                        * To the control name suffix. e.g. (123_23_345_243 - Billing.BillingCategory.Description) **/
                        if (n.BindingName != null && !m_bindings.ContainsKey(lineage))
                        {
                            m_bindings.Add(lineage, n.BindingName);
                            //Debug.WriteLine("Lineage: [" + lineage + "] Binding Name:[" + n.BindingName + "]");

                            /*** Verify if there are properties stored for each node in the DB
                             *  and set them, otherwise just save the properties **/
                            if (n != null && n.BusinessEntity != null && n.Lineage != null)
                            {
                                HandlePropertiesDelegate hpd = HandleProperties;
                                Invoke(hpd, n, propBL, args.DisplayContext);
                            }
                        }
                    }
                }
                if (m_bindings.Count > 0)
                {
                    RootNode.BusinessEntity.ControlBindings = m_bindings;
                }

                #endregion

                if (args.DisplayContext == DisplayContext.GoldCXML)
                {
                    ConfigureGoldTreeDelegate cgtd = TraverseTreeView;
                    Invoke(cgtd, this);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void CopyNodes(CXMLTreeView from, CXMLTreeView to)
        {
            foreach (CXMLTreeNode node in from.Nodes)
            {
                to.Nodes.Add(node.Clone() as CXMLTreeNode);
            }
        }

        private void TraverseTreeView(CXMLTreeView tview)
        {
            //Create a TreeNode to hold the Parent Node
            var temp = new CXMLTreeNode();
            //Loop through the Parent Nodes
            for (int k = 0; k < tview.Nodes.Count; k++)
            {
                //Store the Parent Node in temp
                temp = tview.Nodes[k] as CXMLTreeNode;
                temp.Text = temp.Text.Replace("Type", "");
                //Now Loop through each of the child nodes in this parent node i.e.temp
                for (int i = 0; i < temp.Nodes.Count; i++)
                {
                    //visitChildNodes(temp.Nodes[i] as CXMLTreeNode, temp.Nodes[i] as CXMLTreeNode, null);
                    visitChildNodes(temp.Nodes[i] as CXMLTreeNode);
                }
            }
        }

        private void visitChildNodes(CXMLTreeNode node)
        {
            //Display the Text of the node
            //Debug.WriteLine("node name:" + node.Text + " display in form:" + node.DisplayInForm + " nodescount:" + node.Nodes.Count);
            if (!node.DisplayInForm)
            {
                var parent = node.Parent as CXMLTreeNode;
                TreeNodeCollection children = RemoveNode(node);
                if (parent != null && children != null)
                {
                    foreach (CXMLTreeNode n in children)
                    {
                        Debug.WriteLine("Adding " + n.Text + " to parent:" + parent.Text);
                        parent.Nodes.Add(n);
                    }
                }
            }
            for (int j = 0; j < node.Nodes.Count; j++)
            {
                //Debug.WriteLine("j:[" + j + "] node:" + node.Nodes[j].Text);
                visitChildNodes(node.Nodes[j] as CXMLTreeNode);
            }
        }

        private CXMLTreeNode FirstValidParent(CXMLTreeNode node)
        {
            var parent = node.Parent as CXMLTreeNode;
            if (parent != null)
            {
                if (parent.DisplayInForm)
                {
                    return parent;
                }
                else
                {
                    return FirstValidParent(node.Parent as CXMLTreeNode);
                }
            }
            else
            {
                return node;
            }
        }

        //private void visitChildNodes(CXMLTreeNode node, CXMLTreeNode inparent, CXMLTreeNode tmpparent)
        //{
        //    //Display the Text of the node
        //    //Debug.WriteLine("node name:" + node.Text + " display in form:" + node.DisplayInForm + " nodescount:" + node.Nodes.Count);
        //    if (!node.DisplayInForm)
        //    {
        //        CXMLTreeNode parent = node.Parent as CXMLTreeNode;
        //        TreeNodeCollection children = RemoveNode(node);
        //        if (parent != null && children != null)
        //        {
        //            foreach (CXMLTreeNode n in children)
        //            {
        //                //Debug.WriteLine("Adding " + n.Text + " to parent:" + parent.Text);
        //                //parent.Nodes.Add(n);
        //                visitChildNodes(n, inparent, tmpparent);
        //            }
        //        }
        //    }
        //    else
        //    {
        //        if (tmpparent == null)
        //        {
        //            Debug.WriteLine("Adding " + node.Text + " to parent:" + inparent.Text);
        //            inparent.Nodes.Add(node);
        //        }
        //        else
        //        {
        //            Debug.WriteLine("Adding " + node.Text + " to parent:" + tmpparent.Text);
        //            tmpparent.Nodes.Add(node);
        //        }
        //        if (node.Nodes.Count > 0)
        //        {
        //            tmpparent = node;
        //        }
        //        else
        //        {
        //            tmpparent = null;

        //        }
        //        for (int j = 0; j < node.Nodes.Count; j++)
        //        {
        //            //Debug.WriteLine("j:[" + j + "] node:" + node.Nodes[j].Text);
        //            visitChildNodes(node.Nodes[j] as CXMLTreeNode, inparent, tmpparent);
        //        }
        //    }
        //}
        private TreeNodeCollection RemoveNode(CXMLTreeNode node)
        {
            TreeNodeCollection tnc = null;
            if (node.Nodes.Count > 0)
            {
                tnc = node.Nodes;
            }
            Debug.WriteLine("   Removing " + node.Text);
            node.Remove();
            return tnc;
        }

        /** Verify if props for all contexts are sets, otherwise set them **/

        private void HandleProperties(CXMLTreeNode n, PropertiesBL propBL, DisplayContext context)
        {
            CBFormCtrlItem item =
                ControlFactory.GetPropertiesFromBin(n.BusinessEntity.EntityTypeVersions.EntityTypeVersionsID, n.Lineage,
                                                    context, ControlType.CXMLTreeNode);
            if (item != null && item.CtrlName.Equals("CXMLTreeNode"))
            {
                ControlFactory.SetControlProperties(n, item.PropertyList);
            }
            else
            {
                propBL.SaveControlBinaryProperties(n, n.BusinessEntity.EntityTypeVersions.EntityTypeVersionsID,
                                                   n.Lineage, context, ControlType.CXMLTreeNode);
            }
        }

        public void SetNodeProperties(TreeNode t_node, PropertySet p_set)
        {
            if (p_set == null)
                return;
            t_node.BackColor = (Color) p_set["BackColor"].Value;
            t_node.NodeFont = (Font) p_set["Font"].Value;
        }

        protected override void OnAfterSelect(TreeViewEventArgs e)
        {
            base.OnAfterSelect(e);
            // if node does not have any entityTypeVersionID then exit
            if (e.Node.Tag == null)
            {
                SelectedPropertySet = null;
                OnSelectionChanged(e.Node, null);
                return;
            }

            //Get the propertySet
            PropertySet PropSet = PropertySetCollectionObject.GetByName(e.Node.Text);

            if (PropSet == null)
            {
                SelectedPropertySet = null;
                OnSelectionChanged(e.Node, null);
                return;
            }
            SelectedPropertySet = PropSet;
            OnSelectionChanged(e.Node, SelectedPropertySet);
        }

        protected void OnSelectionChanged(object sender, PropertySet selectedPropertySet)
        {
            // Check if there are any Subscribers
            if (SelectionChanged != null)
            {
                // Call the Event
                SelectionChanged(sender, selectedPropertySet);
            }
        }

        #endregion

        #region ICloneable Members

        object ICloneable.Clone()
        {
            return Clone();
        }

        #endregion

        public virtual CXMLTreeView Clone()
        {
            var tv = MemberwiseClone() as CXMLTreeView;
            return tv;
        }

        private void CXMLTreeView_NodeMouseHover(object sender, TreeNodeMouseHoverEventArgs e)
        {
            OnTreeNodeHover(sender, e);
        }

        private void CXMLTreeView_MouseMove(object sender, MouseEventArgs e)
        {
            //OnTreeViewMouseMove(sender, e);
        }
    }

    public class TreeviewWorkerArgs
    {
        public TreeviewWorkerArgs(BusinessEntity be, DisplayContext context, Type type, object instance)
        {
            DisplayContext = context;
            BusinessEntity = be;
            EntityType = type;
            Instance = instance;
        }

        public Type EntityType { get; set; }
        public BusinessEntity BusinessEntity { get; set; }
        public DisplayContext DisplayContext { get; set; }
        public object Instance { get; set; }
    }
}